class WebAudioLoader {
    load(task) {
        let arrayBuffer = base64ToUint8Array(getRes(task.url));
        return Laya.WebAudioSound.ctx.decodeAudioData(arrayBuffer.buffer);
    }
}

class SpineTempletLoader {
    load(task) {
        let templet = new Laya.SpineTemplet();
        let arrayBuffer = base64ToUint8Array(getRes(task.url)); // .skel
        let atlasUrl = Laya.Utils.replaceFileExtension(task.url, "atlas");
        let atlas = getRes(atlasUrl); // .atlas
        return templet._parse(arrayBuffer.buffer, atlas, task.url, task.progress).then(() => templet);
    }
}

initFakeHttp();
function initFakeHttp() {
    Laya.HttpRequest.prototype.send = send;
    Laya.HttpRequest.prototype.complete = complete;
    Laya.Downloader.prototype.image = image;

    Laya.Loader.registerLoader(["mp3", "wav", "ogg"], WebAudioLoader, Laya.Loader.SOUND);
    Laya.AudioSound.prototype.load = audioLoad;
    Laya.AudioSound.prototype.play = audioPlay;

    Laya.VideoTexture.prototype.appendSource = appendSource;

    Laya.Loader.registerLoader(["skel"], SpineTempletLoader, Laya.Loader.SPINE);
}

// 强制背景音乐使用webAudio,可跟随部分手机静音模式；
forceWebAudio();
function forceWebAudio() {
    var win = Laya.Browser.window;
    var supportWebAudio = win["AudioContext"] || win["webkitAudioContext"] || win["mozAudioContext"] ? true : false;
    if (supportWebAudio) {
        let id = setInterval(() => {
            if (Laya.SoundManager._musicClass && Laya.SoundManager.useAudioMusic == true) {
                Laya.SoundManager.useAudioMusic = false;
            }
            else if (Laya.SoundManager.useAudioMusic == false) {
                clearInterval(id);
            }
        }, 100);
    }
}

// 二进制文件列表
binExt = ["lm", "lani", "bin", "mc"];

function send(url, data, method, responseType, headers) {
    this._responseType = responseType;
    this._url = url;

    this._data = getRes(url);
    // 二进制文件则从base64转回
    if (binExt.includes(getExt(url))) {
        this._data = base64ToUint8Array(this._data);
    }

    complete(this._data, this);
}

function getFileName(url) {
    let arr = url.split("/");
    let fileName = arr[arr.length - 1];
    return fileName;
}

function getExt(url) {
    let fileName = getFileName(url);
    let arr = fileName.split(".");
    return arr[arr.length - 1]
}

function isSameExt(url1, url2) {
    return getExt(url1) == getExt(url2)
}

/**
 * 
 * @param {*} data 
 * @param {js this指向} self 
 */
function complete(data, self) {
    self.clear();
    self.event("complete", data instanceof Array ? [data] : data);
}

function image(owner, url, originalUrl, onProgress, onComplete) {
    let image = new Laya.Browser.window.Image();
    image.crossOrigin = "";
    image.onload = () => {
        image.onload = null;
        image.onerror = null;
        onComplete(image);
    };
    image.onerror = () => {
        image.onload = null;
        image.onerror = null;
        onComplete(null, "");
    };

    image.src = getMediaBase64(url);
    owner.$ref = image; //保持引用避免gc掉
}

function audioLoad(url) {
    this.url = url;
    var ad;
    if (url == Laya.SoundManager._bgMusic) {
        Laya.AudioSound._initMusicAudio();
        ad = Laya.AudioSound._musicAudio;
        if (ad.originalUrl != url) {
            delete Laya.AudioSound._audioCache[ad.originalUrl];
            ad = null;
        }
    } else {
        ad = Laya.AudioSound._audioCache[url];
    }
    if (ad && ad.readyState >= 2) {
        this.event(Event.COMPLETE);
        return;
    }
    if (!ad) {
        if (url == Laya.SoundManager._bgMusic) {
            Laya.AudioSound._initMusicAudio();
            ad = Laya.AudioSound._musicAudio;
        } else {
            ad = (Laya.Browser.createElement("audio"));
        }
        Laya.AudioSound._audioCache[url] = ad;
        Laya.AssetDb.inst.resolveURL(url, url => {
            ad.src = getMediaBase64(url);
        });
    }
    ad.originalUrl = url;

    ad.addEventListener("canplaythrough", onLoaded);
    ad.addEventListener("error", onErr);
    var me = this;
    function onLoaded() {
        offs();
        me.loaded = true;
        me.event(Event.COMPLETE);
    }

    function onErr() {
        ad.load = null;
        offs();
        me.event(Event.ERROR);
    }

    function offs() {
        ad.removeEventListener("canplaythrough", onLoaded);
        ad.removeEventListener("error", onErr);
    }

    this.audio = ad;
    if (ad.load) {
        ad.load();
    } else {
        onErr();
    }
}

function audioPlay(startTime = 0, loops = 0) {
    //trace("playAudioSound");
    if (!this.url)
        return null;

    var ad;
    if (this.url == Laya.SoundManager._bgMusic) {
        ad = Laya.AudioSound._musicAudio;
        if (ad.src != "" && ad.originalUrl != this.url) {  //@fix 清除上一次记录 防止它释放时把音乐暂停了
            delete Laya.AudioSound._audioCache[ad.originalUrl];
            Laya.AudioSound._audioCache[this.url] = ad;
        }
    } else {
        ad = Laya.AudioSound._audioCache[this.url];
    }

    if (!ad) return null;
    var tAd;

    tAd = Laya.Pool.getItem("audio:" + this.url);

    if (Laya.LayaEnv.isConch) {
        if (!tAd) {
            tAd = Laya.Browser.createElement("audio");
            Laya.AssetDb.inst.resolveURL(this.url, url => {
                tAd.src = getMediaBase64(url);
            });
        }
    }
    else {
        if (this.url == Laya.SoundManager._bgMusic) {
            Laya.AudioSound._initMusicAudio();
            tAd = Laya.AudioSound._musicAudio;
            Laya.AssetDb.inst.resolveURL(this.url, url => {
                tAd.src = getMediaBase64(url);
            });
        } else {
            tAd = tAd ? tAd : ad.cloneNode(true);
        }
    }
    ad.originalUrl = this.url;

    var channel = new Laya.AudioSoundChannel(tAd);
    channel.url = this.url;
    channel.loops = loops;
    channel.startTime = startTime;
    channel.play();
    Laya.SoundManager.addChannel(channel);
    return channel;
}

function appendSource(source) {
    var sourceElement = Laya.Browser.createElement("source");
    sourceElement.src = getMediaBase64(source);
    sourceElement.type = "video/" + Laya.Utils.getFileExtension(source);
    this.element.appendChild(sourceElement);
}

function getMediaBase64(url) {
    let base64;
    let ext = getExt(url);
    switch (ext) {
        case "mp3":
            base64 = "data:audio/mpeg;base64," + getRes(url);
            break;
        case "wav":
            base64 = "data:audio/wav;base64," + getRes(url);
            break;
        case "ogg":
            base64 = "data:audio/ogg;base64," + getRes(url);
            break;
        case "mp4":
            base64 = "data:image/video;base64," + getRes(url);
            break;
        case "png":
            base64 = "data:image/png;base64," + getRes(url);
            break;
        case "jpg":
        case "jpeg":
            base64 = "data:image/jpeg;base64," + getRes(url);
            break;
        default:
            break
    }

    return base64;
}

function getRes(url) {
    let maxMatch = 0; // Art/Model/Textures/tu_2.png && res/tu_2.png
    let res;
    for (let key in assetsPackage) {
        if (url.includes(key) && isSameExt(url, key)) { // layaAir.png.json && layaAir.png 
            if (maxMatch < key.length) {
                maxMatch = key.length;
                res = assetsPackage[key];
            }
        }
    }

    return res;
}

function base64ToUint8Array(base64String) {
    const rawData = atob(base64String);
    const outputArray = new Uint8Array(rawData.length);

    for (let i = 0; i < rawData.length; ++i) {
        outputArray[i] = rawData.charCodeAt(i);
    }
    return outputArray;
}
